package com.fzq.config.security;

import com.fzq.util.RedisMapper;
import com.fzq.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 验证jws token合性性过滤器
 * 只做token合法验证和续期
 */
@Component
@Slf4j
public class JwsTokenFilter extends OncePerRequestFilter {
    @Resource
    private RedisMapper redisMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        //如果Authentication有值，证明当前是一个登录请求，直接放行，不在当前filter做处理
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        //证明当前是一个登录请求，直接放行，不在当前filter做处理
        if(authentication!=null){
            filterChain.doFilter(request, response);
            return;
        }

        /*   此处开始说明是非登录请求   */
        //从请求头中获得jws token
        String jwsToken=request.getHeader("token");

        //验证请求头中是否有token，这个类也不处理
        if(StringUtils.isEmpty(jwsToken)){
            filterChain.doFilter(request, response);
            return;
        }

        //请求中有token,但token非法
        if(TokenUtil.verify(jwsToken)==false){
            filterChain.doFilter(request, response);
            return;
        }

        //请求中有token,并合法,从redis中取出token和权限
        String account=TokenUtil.getUserName(jwsToken);  //解析出请求头中token里保存的用户名
        String redisToken= (String) redisMapper.getKey(account+":login:token");

        if(redisToken==null){
            filterChain.doFilter(request, response);
            return;
        }

        if(!redisToken.equals(jwsToken)){
            filterChain.doFilter(request, response);
            return;
        }

        //获得用户的权限
        String redisAuthor= (String) redisMapper.getKey(account+":author");
        //token合法且在有效期内，续期
        redisMapper.setKey(account+":login:token", redisToken, TokenUtil.TIMEOUT, TokenUtil.TIMEUNIT);
        redisMapper.setKey(account+":author", redisAuthor,TokenUtil.TIMEOUT, TokenUtil.TIMEUNIT);


        /* 将jws token转为securty的AuthenticationToken */
        //获得token中的username
        String username=TokenUtil.getUserName(jwsToken);
        //从redis中获得用户的权限，并转为List<String>集合
        List<String> preCodes= Arrays.asList(redisAuthor.split(","));
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        preCodes.forEach(preCode -> {
            authorities.add(new SimpleGrantedAuthority(preCode));
        });

        //将消息封装到认证对象中
        Authentication authen =
                new UsernamePasswordAuthenticationToken(username, "", authorities);


        //将UsernamePasswordAuthenticationToken保存到security上下文的Authentication对象中
        SecurityContextHolder.getContext().setAuthentication(authen);
        filterChain.doFilter(request, response);//放行到下一个过滤器
    }
}
